package org.zyj.io.example.echo;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.nio.charset.StandardCharsets;

public class EchoServer {

    public static final int SERVER_PORT = 11222;

    public static void main(String[] args) throws Throwable {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<NioSocketChannel>() {
                        @Override
                        public void initChannel(NioSocketChannel ch) {//每次建立连接的时候都会被调用
                            ch.pipeline().addLast(new EchoServerHandler());
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 128)// 套接字listen函数中的backlog参数, 等待处理连接的队列大小; 如果backlog过小，就可能出现Accept的速度跟不上，A,B队列满了，就会导致客户端无法建立连接
                    .childOption(ChannelOption.SO_KEEPALIVE, true);
            ChannelFuture f = b.bind(SERVER_PORT).sync();
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

    public static class EchoServerHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            ByteBuf receivedMsg = (ByteBuf) msg;
            System.out.println(receivedMsg.toString(StandardCharsets.UTF_8));//打印一下第一个传进来的msg是什么

            //ChannelHandlerContext对象提供了多种操作, 是你可以出发各种IO事件和IO操作
//            ctx.write(msg); //直接将msg写入channel中, 不需要显示的释放ByteBuf, Netty会帮我们释放
            //一个TCP消息包, 只发送一点点数据, 就很浪费网络, 包头是固定长度
            //所以ctx.write(msg) 这一步仅仅只是写入缓存中, 并没有真正发送出去
            //想要立刻发送出去, 需要显示的调用ctx.flush()
//            ctx.flush();//将缓存中的数据发送出去

            //或者可以简单的使用一行代码来简洁的表示
            ctx.writeAndFlush(msg);
        }
    }
}
